package com.hq.ims.data.utils;

import com.hq.utils.util.BigDecimalUtil;
import com.hq.utils.util.ListUtils;
import com.hq.utils.util.StringUtils;
import lombok.Data;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
 * 相拟度工具
 * <p>
 * jbp
 */
public class SimilarityUtils {

    /**
     * 调用 @link SimilarityUtils.calcSimilarity()
     */
    public static BigDecimal calcSimilarity(
            Map<String, String> mapData,
            List<Map<String, String>> dataList,
            Map<String, SimilarityUtils.SimilarityRule> ruleMap
    ) {
        return calcSimilarity(mapData, dataList, ruleMap, (d) -> {
        });
    }

    /**
     * 计算相拟率
     *
     * @param mapData  需要比较的数据,其中id必须存在,其它字段也必须存在 ruleMap 的key中
     * @param dataList 被比较的数据列表,其中id必须存在,其它字段也必须存在 ruleMap 的key中
     * @param ruleMap  规则列表,key为mapData或dataList中的key,value为
     * @param supplier 计算完后需要处理的方法
     * @return 返回总体计算值
     */
    public static BigDecimal calcSimilarity(
            Map<String, String> mapData,
            List<Map<String, String>> dataList,
            Map<String, SimilarityUtils.SimilarityRule> ruleMap,
            Consumer<List<SimilarityUtils.SimilarityRate>> supplier
    ) {
        //声明比较结果
        List<SimilarityUtils.SimilarityRate> similarityRateList = new ArrayList<>();
        //开始比较
        for (Map<String, String> map : dataList) {
            String compareDataId = mapData.getOrDefault("id", StringUtils.EMPTY);
            String beCompareDataId = map.getOrDefault("id", StringUtils.EMPTY);

            //声明这条数据的比较结果
            SimilarityUtils.SimilarityRate similarityRate = new SimilarityUtils.SimilarityRate();
            similarityRateList.add(similarityRate);
            //构造
            similarityRate.setCompareDataId(compareDataId);
            similarityRate.setBeCompareDataId(beCompareDataId);

            //以规则开始循环字段相似率
            ruleMap.forEach((filedName, similarityRule) -> {
                //字段要比较的值
                String compareValue = mapData.getOrDefault(filedName, StringUtils.EMPTY);
                //字段被比较的值
                String bCompareValue = map.getOrDefault(filedName, StringUtils.EMPTY);
                //字段占比权重
                BigDecimal filedSetWeight = BigDecimalUtil.divide(similarityRule.getSimilarityWeight(), BigDecimalUtil.newBigDecimal("10"));
                //字段相似度
                BigDecimal fieldSimilarityRate = BigDecimalUtil.newBigDecimal(StringUtils.similarityPercent(compareValue, bCompareValue)).multiply(BigDecimalUtil.newBigDecimal("100"));

                SimilarityUtils.SimilarityFieldRate fieldSimilarityFieldRate = new SimilarityUtils.SimilarityFieldRate();
                similarityRate.getSimilarityFieldRateList().add(fieldSimilarityFieldRate);
                fieldSimilarityFieldRate.setFieldName(filedName);
                fieldSimilarityFieldRate.setCompareDataValue(compareValue);
                fieldSimilarityFieldRate.setBeCompareDataValue(bCompareValue);
                fieldSimilarityFieldRate.setSimilarityRate(fieldSimilarityRate);
                fieldSimilarityFieldRate.setWeightSimilarityRate(fieldSimilarityRate.multiply(filedSetWeight));
            });

            //总体相拟率
            similarityRate.setWeightSimilarityRate(ListUtils.sumBigDecimal(similarityRate.getSimilarityFieldRateList(), d -> d.getWeightSimilarityRate()));
        }

        //取高最相拟率
        SimilarityUtils.SimilarityRate similarityRate = ListUtils.sortBigDecimal(similarityRateList, d -> d.getWeightSimilarityRate(), false).get(0);
        //设置消费
        supplier.accept(similarityRateList);
        return similarityRate.getWeightSimilarityRate();
    }

    /**
     * 相似度总体的计算
     */
    @Data
    public static class SimilarityRate {

        /**
         * 权重后的相似率
         */
        public BigDecimal weightSimilarityRate;
        /**
         * 字段比较
         */
        List<SimilarityUtils.SimilarityFieldRate> similarityFieldRateList = new ArrayList<>();
        /**
         * 比较的数据ID
         */
        private String compareDataId;
        /**
         * 被比较数据的ID
         */
        private String beCompareDataId;
    }

    /**
     * 相似度字段的计算
     */
    @Data
    public static class SimilarityFieldRate {

        /**
         * 规则名称
         */
        public String fieldName;
        /**
         * 相似率
         */
        public BigDecimal similarityRate;
        /**
         * 权重后的相似率
         */
        public BigDecimal weightSimilarityRate;
        /**
         * 比较的数据ID
         */
        private String compareDataValue;
        /**
         * 被比较数据的ID
         */
        private String beCompareDataValue;
    }

    /**
     * 相似度规则
     */
    @Data
    public static class SimilarityRule {

        /**
         * 相拟度权重
         */
        public BigDecimal similarityWeight;

    }
}
